import { MultipartFile } from '@fastify/multipart'
import { Inject, Injectable, Logger, NotFoundException } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm'
import dayjs from 'dayjs'
import { isNil } from 'lodash'
import { Repository } from 'typeorm'
import { Storage } from '~/modules/tools/storage/storage.entity'
import { AliyunOssService } from '~/shared/aliyun-oss/aliyun-oss.service'

import {
  deleteFile,
  fileRename,
  getExtname,
  getFileFullPath,
  getFilePath,
  getFileType,
  getSize,
  saveLocalFile,
	getOssDirPath
} from '~/utils/file.util'

@Injectable()
export class UploadService {
	private readonly logger = new Logger(UploadService.name)

  constructor(
    @InjectRepository(Storage)
    private storageRepository: Repository<Storage>,
		private aliyunOssService: AliyunOssService,
  ) {}

  /**
   * 保存文件上传记录
   */
  async saveFile(file: MultipartFile & Record<string, any>): Promise<string> {
    if (isNil(file))
      throw new NotFoundException('Have not any file to upload!')

    const fileName = file.filename
    const size = getSize(file.file?.bytesRead ?? 0)
    const extName = getExtname(fileName)
    const type = getFileType(extName)
    const name = fileRename(fileName)
    const currentDate = dayjs().format('YYYY-MM-DD')
    const path = getFilePath(name, currentDate, type)

    if (file.toBuffer) {
      await saveLocalFile(await file.toBuffer(), name, currentDate, type)
    }
    // 判断 file.data 为Buffer类型
    if (Buffer.isBuffer(file.data)) {
      await saveLocalFile(file.data, name, currentDate, type)
    }

    try {
			// 保存到阿里云OSS服务器中
			const ossKey = getOssDirPath(currentDate, type, name)
			const ossUrl = await this.aliyunOssService.putOssFile(ossKey, path)
			this.logger.log(`save file path: ${path}: ${ossUrl}`)

			await this.storageRepository.save({
				name,
				fileName,
				extName,
				path,
				type,
				size,
				ossPath: ossKey,
				ossFullPath: ossUrl
			})

			return ossUrl
		} catch (error) {
			this.logger.error(error)
			throw new Error('Save file failed!')
		}
  }

  async removeFile(path: string) {
    const storage = await this.storageRepository.findOne({ where: { path } })
    if (isNil(storage)) {
      throw new NotFoundException('File not found!')
    }

    await this.storageRepository.delete(storage.id)

    // 删除文件
    await deleteFile(path)
  }
}
